using System.Collections.Generic;
using System.Linq;
using ODT.Common.ExtensionMethods;
using ODT.Intellisense.Core;
using ODT.Intellisense.Models;

namespace ODT.Intellisense.Services
{
	internal sealed class InputProcessingService : IInputProcessingService
	{
		private const char WordSeparator = '.';

		private readonly IReadOnlyList<char> numbers;

		private readonly IReadOnlyList<char> compoundSeparators;

		private readonly IReadOnlyList<char> wordAndCompoundSeparators;

		public InputProcessingService()
		{
			wordAndCompoundSeparators = new List<char>(compoundSeparators = new List<char> { ' ', '=', '+', '-', '*', '/' }) { '.' };
			numbers = "0123456789".ToList();
		}

		public string[] GetWords(string input)
		{
			input.ThrowArgumentNullException("input");
			List<string> list = ProcessInput(input);
			if (list.Count == 0)
			{
				return new string[0];
			}
			List<string> list2 = new List<string>();
			foreach (string item in list)
			{
				if (!wordAndCompoundSeparators.Contains(item[0]))
				{
					list2.Add(item);
				}
			}
			return list2.ToArray();
		}

		public string GetLastWord(string input)
		{
			input.ThrowArgumentNullException("input");
			List<string> list = ProcessInput(input);
			if (list.Count == 0)
			{
				return string.Empty;
			}
			string text = list.Last();
			if (wordAndCompoundSeparators.Contains(text[0]))
			{
				return string.Empty;
			}
			return text;
		}

		public string GetBeforeLastWord(string input)
		{
			input.ThrowArgumentNullException("input");
			string lastWord = GetLastWord(input);
			return input.Substring(0, input.Length - lastWord.Length);
		}

		public string GetPrefixOfLastCompound(string input)
		{
			input.ThrowArgumentNullException("input");
			List<string> list = ProcessInput(input);
			if (list.Count < 2)
			{
				return string.Empty;
			}
			string text = string.Empty;
			for (int i = 0; i < list.Count - 1; i++)
			{
				text += list[i];
				if (compoundSeparators.Contains(list[i][0]))
				{
					text = string.Empty;
				}
			}
			return text;
		}

		private List<string> ProcessInput(string input)
		{
			List<string> list = new List<string>();
			ReadingInputState readingInputState = ReadingInputState.CompoundStart;
			string part = string.Empty;
			for (int i = 0; i < input.Length; i++)
			{
				char c = input[i];
				switch (readingInputState)
				{
				case ReadingInputState.CompoundStart:
					if (wordAndCompoundSeparators.Contains(c))
					{
						part += c;
						continue;
					}
					CommitPart(list, ref part);
					readingInputState = ((char.ToLower(c) == 'j') ? ReadingInputState.StartWithJ : ((!numbers.Contains(c)) ? ReadingInputState.ReadingChar : ReadingInputState.NumbersOnly));
					break;
				case ReadingInputState.NumbersOnly:
					if (numbers.Contains(c))
					{
						part += c;
						continue;
					}
					if (compoundSeparators.Contains(c))
					{
						CommitPart(list, ref part);
						readingInputState = ReadingInputState.CompoundStart;
					}
					else
					{
						readingInputState = ReadingInputState.ReadingChar;
					}
					break;
				case ReadingInputState.ReadingChar:
					if (c == '.')
					{
						CommitPart(list, ref part);
						readingInputState = ReadingInputState.WordStart;
					}
					else if (compoundSeparators.Contains(c))
					{
						CommitPart(list, ref part);
						readingInputState = ReadingInputState.CompoundStart;
					}
					break;
				case ReadingInputState.WordStart:
					if (c == '.')
					{
						part += c;
						continue;
					}
					if (compoundSeparators.Contains(c))
					{
						readingInputState = ReadingInputState.CompoundStart;
						break;
					}
					CommitPart(list, ref part);
					readingInputState = ReadingInputState.ReadingChar;
					break;
				}
				part += c;
			}
			if (readingInputState == ReadingInputState.CompoundStart)
			{
				BlendPart(list, ref part);
			}
			else
			{
				CommitPart(list, ref part);
			}
			return list;
		}

		private void CommitPart(List<string> parts, ref string part)
		{
			if (!string.IsNullOrEmpty(part))
			{
				parts.Add(part);
				part = string.Empty;
			}
		}

		private void BlendPart(List<string> parts, ref string part)
		{
			if (!string.IsNullOrEmpty(part))
			{
				if (parts.Count == 0)
				{
					parts.Add(part);
				}
				else
				{
					parts[parts.Count - 1] += part;
				}
				part = string.Empty;
			}
		}
	}
}
